#include "logger.h"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/details/registry.h>
#include <spdlog/async.h>
#include <QDir>
#include <QDebug>  // 添加这个头文件
#include <QSettings>
#include <QStandardPaths>
#include <QDateTime>
#include <QFile>   // 添加QFile头文件，用于崩溃日志写入
#include <QCoreApplication>
#ifdef Q_OS_WIN
#include <Windows.h>
#endif

Logger* Logger::s_instance = nullptr;


std::unordered_map<std::string, Logger::LogLevel>& Logger::getFileLogLevels() {
	static std::unordered_map<std::string, Logger::LogLevel> fileLogLevels;
	return fileLogLevels;
}

void Logger::setFileLogLevel(const char* file, LogLevel level) {
	if (!file) return;  // 防止空指针

	try {
		// 提取文件名，而非使用完整路径
		std::string fileName = extractFileName(file).toStdString();
		// 使用getFileLogLevels()函数访问映射表
		getFileLogLevels()[fileName] = level;
	}
	catch (const std::exception& ex) {
		qCritical() << "Failed to set file log level: " << ex.what();
	}
}

Logger::LogLevel Logger::getFileLogLevel(const char* file) {
	if (!file) return Logger::instance()->level();

	try {
		// 提取文件名
		std::string fileName = extractFileName(file).toStdString();

		// 使用getFileLogLevels()函数访问映射表
		auto& levels = getFileLogLevels();
		auto it = levels.find(fileName);
		if (it != levels.end()) {
			return it->second;
		}
	}
	catch (const std::exception& ex) {
		qCritical() << "Failed to get file log level: " << ex.what();
	}

	return Logger::instance()->level();
}
Logger* Logger::instance()
{
	if (!s_instance) {
		s_instance = new Logger();
	}
	return s_instance;
}

Logger::Logger(QObject* parent)
	: QObject(parent)
	, m_logPath(QCoreApplication::applicationDirPath() + "/logs")
	, m_crashLogPath(QCoreApplication::applicationDirPath() + "/crash_logs")
	, m_logPattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%t] %v")
	, m_maxFileSize(5 * 1024 * 1024) // 5MB
	, m_maxFiles(10)
	, m_level(Debug)
	, m_asyncMode(true)
{
	// 确保日志目录存在
	QDir logDir(m_logPath);
	if (!logDir.exists()) {
		logDir.mkpath(".");
	}
	
	// 确保崩溃日志目录存在
	QDir crashLogDir(m_crashLogPath);
	if (!crashLogDir.exists()) {
		crashLogDir.mkpath(".");
	}

	initialize();
}

Logger::~Logger()
{
	// 刷新日志
	spdlog::shutdown();
}

void Logger::writeCrashLog(const QString& crashInfo)
{
	if (!s_instance) return;
	
	QString logFilePath = s_instance->m_crashLogPath + 
		QString("/crash_%1.log").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
	
	QFile file(logFilePath);
	if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
		QTextStream out(&file);
		out << crashInfo;
		file.close();
	}
	
	// 同时记录到常规日志
	s_instance->critical("崩溃日志已保存到: " + logFilePath);
}

void Logger::setCrashLogPath(const QString& path)
{
	m_crashLogPath = path;
	QDir dir(path);
	if (!dir.exists()) {
		dir.mkpath(".");
	}
}

QString Logger::crashLogPath() const
{
	return m_crashLogPath;
}

void Logger::initialize()
{
	try {
		// 删除以下代码，它导致了更严重的问题
		/*
		#ifdef Q_OS_WIN
		static UINT oldCP = GetConsoleOutputCP();
		SetConsoleOutputCP(CP_UTF8);
		#endif
		*/

		// 如果选择异步模式，设置异步队列
		if (m_asyncMode) {
			spdlog::init_thread_pool(8192, 1);
		}

		// 设置全局日志格式
		spdlog::set_pattern(m_logPattern.toStdString());

		// 设置控制台和文件日志
		setupConsoleLogger();
		setupFileLogger();

		// 设置全局日志级别
		spdlog::set_level(toSpdLogLevel(m_level));
	}
	catch (const std::exception& ex) {
		qCritical() << "Failed to initialize logger: " << ex.what();
	}
}

void Logger::setupConsoleLogger()
{
	// 创建控制台日志
	m_consoleLogger = spdlog::stdout_color_mt("console");
}

void Logger::setupFileLogger()
{
	try {
		// 创建日志文件名
		QString logFileName = m_logPath + "/app.log";

		if (m_asyncMode) {
			// 创建异步文件日志
			m_fileLogger = spdlog::rotating_logger_mt<spdlog::async_factory>(
				"file_logger",
				logFileName.toStdString(),
				m_maxFileSize,
				m_maxFiles
			);
		}
		else {
			// 创建同步文件日志
			m_fileLogger = spdlog::rotating_logger_mt(
				"file_logger",
				logFileName.toStdString(),
				m_maxFileSize,
				m_maxFiles
			);
		}
	}
	catch (const std::exception& ex) {
		qCritical() << "Failed to setup file logger: " << ex.what();
	}
}

spdlog::level::level_enum Logger::toSpdLogLevel(LogLevel level) const
{
	switch (level) {
	case Trace:    return spdlog::level::trace;
	case Debug:    return spdlog::level::debug;
	case Info:     return spdlog::level::info;
	case Warning:  return spdlog::level::warn;
	case Error:    return spdlog::level::err;
	case Critical: return spdlog::level::critical;
	case Off:      return spdlog::level::off;
	default:       return spdlog::level::info;
	}
}

Logger::LogLevel Logger::fromSpdLogLevel(spdlog::level::level_enum level) const
{
	switch (level) {
	case spdlog::level::trace:    return Trace;
	case spdlog::level::debug:    return Debug;
	case spdlog::level::info:     return Info;
	case spdlog::level::warn:     return Warning;
	case spdlog::level::err:      return Error;
	case spdlog::level::critical: return Critical;
	case spdlog::level::off:      return Off;
	default:                      return Info;
	}
}

bool Logger::shouldLog(Logger::LogLevel msgLevel, const char* file) const {
	// 首先检查文件级别
	if (file) {
		try {
			std::string fileName = extractFileName(file).toStdString();

			// 使用getFileLogLevels()函数访问映射表
			auto& levels = getFileLogLevels();
			auto it = levels.find(fileName);
			if (it != levels.end()) {
				return msgLevel >= it->second;
			}
		}
		catch (const std::exception& ex) {
			qCritical() << "Error checking log level: " << ex.what();
		}
	}

	// 如果没有设置文件级别，则使用全局级别
	return msgLevel >= m_level;
}

void Logger::log(LogLevel level, const QString& message, const char* file, int line, const char* function)
{
	// 检查是否应该记录此级别的日志
	if (!shouldLog(level, file)) {
		return;
	}

	try {
		// 准备带有元信息的消息
		QString formattedMsg;
		if (file && line && function) {
			// 使用文件名而不是完整路径
			QString shortFileName = extractFileName(file);

			formattedMsg = QString("[%1:%2:%3] %4")
				.arg(shortFileName).arg(line).arg(function).arg(message);
		}
		else {
			formattedMsg = message;
		}

		// 注意：这里是重点修改，确保UTF-8字符串转换正确
		QByteArray utf8Data = formattedMsg.toUtf8();
		std::string stdMsg(utf8Data.constData(), utf8Data.length());
		auto spdLevel = toSpdLogLevel(level);

		// 记录到控制台和文件
		if (m_consoleLogger) m_consoleLogger->log(spdLevel, stdMsg);
		if (m_fileLogger) m_fileLogger->log(spdLevel, stdMsg);
	}
	catch (const std::exception& ex) {
		qCritical() << "Log failed: " << ex.what();
	}
}

void Logger::debug(const QString& message, const char* file, int line, const char* function)
{
	log(Debug, message, file, line, function);
}

void Logger::info(const QString& message, const char* file, int line, const char* function)
{
	log(Info, message, file, line, function);
}

void Logger::warning(const QString& message, const char* file, int line, const char* function)
{
	log(Warning, message, file, line, function);
}

void Logger::error(const QString& message, const char* file, int line, const char* function)
{
	log(Error, message, file, line, function);
}

void Logger::critical(const QString& message, const char* file, int line, const char* function)
{
	log(Critical, message, file, line, function);
}

void Logger::setLevel(LogLevel level)
{
	m_level = level;
	spdlog::set_level(toSpdLogLevel(level));
}

Logger::LogLevel Logger::level() const
{
	return m_level;
}

void Logger::setFilePath(const QString& path)
{
	m_logPath = path;
}

void Logger::setMaxFileSize(size_t maxSize)
{
	m_maxFileSize = maxSize;
}

void Logger::setMaxFiles(size_t maxFiles)
{
	m_maxFiles = maxFiles;
}

void Logger::setPattern(const QString& pattern)
{
	m_logPattern = pattern;
	spdlog::set_pattern(pattern.toStdString());
}

void Logger::setAsyncMode(bool enabled)
{
	m_asyncMode = enabled;
}

QString Logger::extractFileName(const char* fullPath)
{
	if (!fullPath) return QString();

	// 寻找最后一个路径分隔符
	const char* lastSlash = strrchr(fullPath, '/');
	const char* lastBackslash = strrchr(fullPath, '\\');

	// 确定最后一个分隔符
	const char* lastSeparator = lastSlash > lastBackslash ? lastSlash : lastBackslash;

	// 如果没有分隔符，返回原始路径
	if (!lastSeparator) return QString(fullPath);

	// 返回文件名部分
	return QString(lastSeparator + 1);
}

void Logger::flush()
{
	try {
		// 刷新控制台日志
		if (m_consoleLogger) {
			m_consoleLogger->flush();
		}

		// 刷新文件日志
		if (m_fileLogger) {
			m_fileLogger->flush();
		}

		// 获取所有已注册的日志器并刷新
		// 注意：不同版本的spdlog有不同的API，使用内置函数
		try {
			// 使用spdlog的内置函数刷新所有日志器
			spdlog::apply_all([](std::shared_ptr<spdlog::logger> l) {
				l->flush();
				});
		}
		catch (const std::exception&) {
			// 如果apply_all不可用，尝试另一种方法
			spdlog::drop_all(); // 刷新并关闭所有日志器

			// 重新设置我们的日志器，确保不会丢失
			if (m_consoleLogger)
				spdlog::register_logger(m_consoleLogger);
			if (m_fileLogger)
				spdlog::register_logger(m_fileLogger);
		}
	}
	catch (const std::exception& ex) {
		qCritical() << "Failed to flush loggers: " << ex.what();
	}
}

bool Logger::loadConfig(const QString& configFile)
{
	QSettings settings(configFile, QSettings::IniFormat);

	settings.beginGroup("Logging");

	// 读取日志级别
	QString levelStr = settings.value("Level", "Debug").toString();
	if (levelStr == "Trace") setLevel(Trace);
	else if (levelStr == "Debug") setLevel(Debug);
	else if (levelStr == "Info") setLevel(Info);
	else if (levelStr == "Warning") setLevel(Warning);
	else if (levelStr == "Error") setLevel(Error);
	else if (levelStr == "Critical") setLevel(Critical);
	else if (levelStr == "Off") setLevel(Off);

	// 读取其他设置
	setFilePath(settings.value("Path", m_logPath).toString());
	setMaxFileSize(settings.value("MaxFileSize", QVariant::fromValue(static_cast<qulonglong>(m_maxFileSize))).toULongLong());
	setMaxFiles(settings.value("MaxFiles", QVariant::fromValue(static_cast<quint32>(m_maxFiles))).toUInt());
	setPattern(settings.value("Pattern", m_logPattern).toString());
	setAsyncMode(settings.value("AsyncMode", m_asyncMode).toBool());

	settings.endGroup();

	// 重新初始化日志系统
	initialize();

	return true;
}

bool Logger::saveConfig(const QString& configFile) const
{
	QSettings settings(configFile, QSettings::IniFormat);

	settings.beginGroup("Logging");

	// 保存日志级别
	QString levelStr;
	switch (m_level) {
	case Trace: levelStr = "Trace"; break;
	case Debug: levelStr = "Debug"; break;
	case Info: levelStr = "Info"; break;
	case Warning: levelStr = "Warning"; break;
	case Error: levelStr = "Error"; break;
	case Critical: levelStr = "Critical"; break;
	case Off: levelStr = "Off"; break;
	}
	settings.setValue("Level", levelStr);

	// 保存其他设置
	settings.setValue("Path", m_logPath);
	settings.setValue("MaxFileSize", QVariant::fromValue(static_cast<qulonglong>(m_maxFileSize)));
	settings.setValue("MaxFiles", QVariant::fromValue(static_cast<quint32>(m_maxFiles)));
	settings.setValue("Pattern", m_logPattern);
	settings.setValue("AsyncMode", m_asyncMode);

	settings.endGroup();
	settings.sync();

	return true;
}

// Qt消息系统集成
void myMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
	Logger::LogLevel level;
	switch (type) {
	case QtDebugMsg: level = Logger::Debug; break;
	case QtInfoMsg: level = Logger::Info; break;
	case QtWarningMsg: level = Logger::Warning; break;
	case QtCriticalMsg: level = Logger::Error; break;
	case QtFatalMsg: level = Logger::Critical; break;
	}

	// 对于Qt消息系统，始终使用全局日志级别（-1表示使用全局级别）
	Logger::instance()->log(level, msg, context.file, context.line, context.function);
}


LogStream::LogStream(Logger::LogLevel level, const char* file, int line, const char* function)
	: m_level(level)
	, m_file(file)
	, m_line(line)
	, m_function(function)
	, m_shouldLog(Logger::instance()->shouldLog(level, file))
	, m_string()
	, m_buffer(&m_string)
{
	// Qt6默认使用UTF-8编码，不需要手动设置
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
	// Qt5需要手动设置编码
	m_buffer.setCodec("UTF-8");
#endif
}

LogStream::~LogStream() {
	if (m_shouldLog) {
		Logger::instance()->log(m_level, m_string, m_file, m_line, m_function);
	}
}